package mpicbg.models;


import java.io.*;
import ij.ImagePlus;
import ij.gui.NewImage;
import ij.process.*;


/* Read images from a directory using ImageJ's utilities. 
 * Add channel number  (r or g or b) as an input option for RGB images. 
 * This class can read data for CV mode or TT mode.  
 * In TT mode, diretory is used as training directory.
 */ 
public class DataInput
{
	//problem properties
	protected byte[][] data = null;
	protected ImagePlus data1;
	protected ImagePlus data2;
	protected byte[][] testingData = null;
	String[] children = null; //list of image file names in the dir
	String[] testingChildren = null; //list of testing image file names in the testdir
	protected int height = 0;
	protected int width = 0;
	String directory;
	String ext;
	String testDirectory;
	String testExt;

	String channel = "g";
	boolean resize = false;

	public DataInput(String directory, String ext, String channel)
	{
		this.directory = directory;
		this.ext = ext;
		this.channel = channel;
	}

	//TT mode
	public DataInput(String trainDir, String trainExt, String testDir, String testExt, String channel)
	{
		this.directory = trainDir;
		this.ext = trainExt;
		this.channel = channel;
		this.testDirectory = testDir;
		this.testExt = testExt;
	}
	
	//if the image is to be resized before processing
	public DataInput(String directory, String ext, String channel, int newwidth, int newheight)
	{
		this.directory = directory;
		this.ext = ext;
		this.channel = channel;
		this.height = newheight;
		this.width = newwidth;
		resize = true;
	}

	//This constructor uses the default channel setting or when the image is b/w.
	public DataInput(String directory, String ext)
	{
		this.directory = directory;
		this.ext = ext;
	}

/*
	void openOneImage(String path, byte[] pixels, byte[] tmppixels)
	{

		System.out.println(path);
		//ImagePlus has method such as getFileInfo, getStatistics, getPixel.
		ImagePlus imgp = new ImagePlus(path); //calls the opener.openImage()
		//System.out.println(imgp.getFileInfo());
		//imgp.show();

		ImageProcessor ip = imgp.getProcessor();

		if (resize)
			ip  = ip.resize(width,height);

		int width = ip.getWidth();
		int height = ip.getHeight();
		//width and height should be the same for all images. -- error handling
		if(width != this.width || height != this.height)
		{
			System.err.println("Image" + path + "is not the same size as the 1st one. Ignored.");
			return;
		}

		//get the pixel values. We only deal with the one color for RGB picture
		if (ip instanceof ByteProcessor)
		{
			System.out.println("8-bit image..");
			//should use array copy since memory was also allocated in ip?
			pixels = (byte[]) (ip.getPixels());
		}
		else if (ip instanceof ColorProcessor)
		{
			//System.out.println("RGB image..");
			//note: tmppixels contains the irrelevant channels.
			if (channel == "r")
				((ColorProcessor)ip).getRGB(pixels,tmppixels,tmppixels);
			else if (channel == "g")
				((ColorProcessor)ip).getRGB(tmppixels,pixels,tmppixels);
			else
				((ColorProcessor)ip).getRGB(tmppixels,tmppixels,pixels);

			//debug: show the image
			if(annotool.Annotator.debugFlag.equals("true"))
			{
				ImagePlus testimg = NewImage.createByteImage(path+":channel "+channel,  width, height, 1, NewImage.FILL_BLACK);
				ImageProcessor test_ip = testimg.getProcessor();
				test_ip.setPixels(pixels);
				testimg.show();
				//testimg.updateAndDraw();
			}
		}
		else
			System.err.println("ImageProcessor: not a ByteProcessor or ColorProcessor. (Maybe Float or ShortProcessor.)");
	}*/

	public ImagePlus[] readImagePlus(String directory, String ext)
	{
		String[] children= getChildren(directory, ext);
		//read the 1st one to get some properties
		//System.out.println("The first image in dir is "+ children[0] + ". Reading total "+ children.length + " images ..");
		ImagePlus[] data2 = new ImagePlus[children.length];
		for(int i=0;i<children.length;i++)
		{
			data2[i] = new ImagePlus(directory+children[i]);
		}	

		return data2;
	}
	
	private byte[][] readImages(String directory, String ext, String[] children)
	{
		//read the 1st one to get some properties
		//System.out.println("The first image in dir is "+ children[0] + ". Reading total "+ children.length + " images ..");
		ImagePlus imgp = new ImagePlus(directory+children[0]);

		if (!resize)
		{
			width = imgp.getProcessor().getWidth();
			height = imgp.getProcessor().getHeight();
		}

		//allocate the memory for the problem
		int length = children.length;
		data= new byte[length][width*height];
		//used as temporary storage for irrelevant channels (color image)
		byte[] tmppixels= new byte[width*height];

		//fill the data
	//	for (int i=0; i<length; i++)
	//		openOneImage(directory+children[i], data[i], tmppixels);

		//debug:
		//for (int i=0; i<length; i++)
		//{
		//  System.out.print("\nImage "+i+": ");
		//  for (int j=0; j<width*height; j++)
		//  {
		//     System.out.print(data[i][j]&0xff);
		//     System.out.print(" ");
		//  }
		//}

		return data;
	}
	/** return the pixel data -- use a mask to avoid sign extension
	  		such as data[i][j]&0xff
	  		The data is for CV mode, or training data in TT mode.
	 **/
	public byte[][] getData()
	{
		if (data == null)
		{
			String[] children = getChildren();
			data = 	readImages(directory, ext, children);
		}
		return data;
	}

	public byte[][] getTrainingData()
	{
		return getData();
	}
	
	/*
	 * return the pixel data -- use a mask to avoid sign extension
	  		such as data[i][j]&0xff
	 * Testing Data in TT mode
	 * 
	 */
	public byte[][] getTestingData()
	{
		if (testingData == null)
		{
			String[] testingChildren = getTestChildren();
		    testingData = readImages(testDirectory, testExt, testingChildren);
		}
		return testingData;
	}
	
	//getter should be called by images are read.
	public int getLength()
	{
		if (children == null)
			System.err.println("Warning: Images should be read first.");

		return children.length;
	}

	public int getTrainingLength()
	{
	    return getLength();
	}
	public int getTestingLength()
	{
		if (testingChildren == null)
			System.err.println("Warning: Images should be read first.");
		return testingChildren.length;
	}

	public int getWidth()
	{
		if(width == 0)
			System.err.println("Warning: Images should be read first.");

		return width;
	}

	public int getHeight()
	{
		if(height == 0)
			System.err.println("Warning: Images should be read first.");

		return height;
	}

	/* this will be called by public interface methods depending on training/testing */
	private String[] getChildren(String directory, final String ext)
	{
		    String[] children;
		
			File dir = new File(directory);
			FilenameFilter filter = new FilenameFilter()
			{
				public boolean accept(File dir, String name)
				{ 
					return name.endsWith(ext);
				}
			};
			children = dir.list(filter);
			if (children == null)
				System.err.println("Problem reading files from the image directory.");
		
		return children;
	}

	//get the testing files or one set CV files
	public String[] getChildren()
	{
		if (children == null)
	   	 children = getChildren(directory, ext);
		
		return children;
	}

	//the same as getChildrent which is used for both training data and CV mode
	public String[] getTrainingChildren()
	{
	    return getChildren();
	}
	
	//get the testing files or one set CV files
	public String[] getTestChildren()
	{
		if (testingChildren == null)
			testingChildren = getChildren(testDirectory, testExt); 
	   	return testingChildren;
	}

	//return true if the images are color images
	public boolean isColor(String path)
	{
		ImagePlus imgp = new ImagePlus(path); 
		ImageProcessor ip = imgp.getProcessor();
		if(ip instanceof ColorProcessor)
		   return true;
	   else
			return false;
	}
	

}